using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace UintyEngineExtensions
{
    public static class UnityEngineUtil
    {
        /// <summary>
        /// 获取 与给定位置 距离最近的目标
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="targets"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        public static T GetCloseTarget<T>(IEnumerable<T> targets, Vector3 position) where T : MonoBehaviour
        {
            if (targets == null) return null;
            var res = targets.OrderBy(x => (x.transform.position - position).sqrMagnitude).ToArray();
            if (res.Length > 0)
            {
                return res[0];
            }

            return null;
        }

        /// <summary>
        /// 按距离排序
        /// </summary>
        /// <param name="targets"></param>
        /// <param name="position"></param>
        /// <param name="???"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IEnumerable<T> GetCloseTargets<T>(IEnumerable<T> targets, Vector3 position, int maxCount)
            where T : MonoBehaviour
        {
            if (targets == null) return null;
            var res = targets.OrderBy(x => (x.transform.position - position).sqrMagnitude)
                .Take(maxCount);
            if (res.Any())
            {
                return res;
            }

            return null;
        }

        public static bool CheckInDistacne2D(Transform a, Transform b, float d)
        {
            var distance = a.position - b.position;
            distance.y = 0;
            return Vector3.Magnitude(distance) <= d;
        }
    }

    public static class UintyEngineExtensionMethods
    {
        #region Collider

        /// <summary>
        /// 两个碰撞体之间都距离.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static float Distance(this Collider a, Collider b)
        {
            return Vector3.Distance(
                a.ClosestPointOnBounds(b.transform.position),
                b.ClosestPointOnBounds(a.transform.position));
        }

        #endregion

        #region Transform

        /// <summary>
        /// a 与 b 的欧氏距离是否小于d
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        public static bool CheckInDistacne2D(this Transform a, Transform b, float d)
        {
            var distance = a.position - b.position;
            distance.y = 0;
            return Vector3.Magnitude(distance) <= d;
        }

        /// <summary>
        /// Performs a deep search for the provided name.
        /// </summary>
        /// <param name="trm">The transform to search through</param>
        /// <param name="name">The name of the transform object to search for.</param>
        /// <returns></returns>
        public static Transform FindRecursive(this Transform trm, string name)
        {
            Transform child = null;

            // Loop through top level
            foreach (Transform t in trm)
            {
                if (t.name == name)
                {
                    child = t;
                    return child;
                }
                else if (t.childCount > 0)
                {
                    child = t.FindRecursive(name);
                    if (child)
                    {
                        return child;
                    }
                }
            }

            return child;
        }

        #endregion

        #region Vector

        public static Vector3 xy2xz(this Vector2 a)
        {
            return new Vector3(a.x, 0, a.y);
        }

        public static Vector2 xz(this Vector3 a)
        {
            return new Vector2(a.x, a.z);
        }

        public static Vector2Int xzInt(this Vector3 a)
        {
            return new Vector2Int((int)a.x, (int)a.z);
        }

        public static Vector2Int xyInt(this Vector3 a)
        {
            return new Vector2Int((int)a.x, (int)a.y);
        }

        public static float DistanceXZ(this Vector3 a, Vector3 b)
        {
            return Vector3.Distance(new Vector3(a.x, 0, a.z), new Vector3(b.x, 0, b.z));
        }

        /// <summary>
        /// 每个轴的差距很小
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool Approximately(this Vector3 a, Vector3 b)
        {
            for (int i = 0; i < 3; i++)
            {
                if (!Mathf.Approximately(a[i], b[i]))
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// 限制精度
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static Vector3 Round(this Vector3 a, int n = 0)
        {
            for (int i = 0; i < 3; i++)
            {
                a[i] = (float)Math.Round(a[i], n);
            }

            return a;
        }

        #endregion
    }
}